package com.vaadin.thomas.contenttool.data;

import java.util.Date;
import java.util.Locale;

import org.neo4j.graphdb.Node;
import org.neo4j.graphdb.NotFoundException;
import org.neo4j.graphdb.Transaction;

import com.vaadin.thomas.contenttool.exceptions.ContentModelException;

public class Localization extends AbstractData implements
		Comparable<Localization> {

	public Localization(Node n) {
		super(n);
	}

	private static final String PROP_VALUE = "value";
	private static final String PROP_LOCALE = "locale";
	/**
	 * LONG!
	 */
	private static final String PROP_START = "start";

	public String getValue() {
		return (String) node.getProperty(PROP_VALUE);
	}

	void setValue(String value) {
		Transaction tx = node.getGraphDatabase().beginTx();
		try {
			node.setProperty(PROP_VALUE, value);
			tx.success();
		} catch (RuntimeException e) {
			tx.failure();
			throw e;
		} finally {
			tx.finish();
		}
	}

	/**
	 * Changes the start date for this {@link Localization}, IF it already has
	 * one.
	 * <p>
	 * Start dates cannot be set for Localizations without one, as that will
	 * create a situation where a Localization has no value for a specific time.
	 * 
	 * @param date
	 *            The new starting date. Can be of any resolution, but
	 *            {@link Date} matching is done to the minute level.
	 */
	public void setStartDate(Date date) {

		if (getStartDate() == null) {
			throw new ContentModelException(
					"Cannot set start date on base value Localization.");
		}

		Transaction tx = node.getGraphDatabase().beginTx();
		try {
			node.setProperty(PROP_START, date.getTime());
			tx.success();
		} catch (RuntimeException e) {
			tx.failure();
			throw e;
		} finally {
			tx.finish();
		}
	}

	public Date getStartDate() {
		try {
			return new Date((Long) node.getProperty(PROP_START));
		} catch (NotFoundException e) {
			return null;
		}
	}

	public void setLanguage(Locale l) {
		Transaction tx = node.getGraphDatabase().beginTx();
		try {
			node.setProperty(PROP_LOCALE, l.getLanguage());
			tx.success();
		} catch (RuntimeException e) {
			tx.failure();
			throw e;
		} finally {
			tx.finish();
		}
	}

	public Locale getLanguage() {
		return new Locale((String) node.getProperty(PROP_LOCALE));
	}

	/**
	 * @see #create(Locale, String, Date)
	 */
	public static Localization create(Locale loc, String value) {
		return create(loc, value, null);
	}

	@Override
	public int compareTo(Localization other) {

		if (getLanguage().equals(other.getLanguage())) {

			// sort by start date, null first
			if (getStartDate() == null) {
				return -1;
			}
			if (other.getStartDate() == null) {
				return 1;
			}
			return getStartDate().compareTo(other.getStartDate());

		} else {

			// sort alphabetically by language code
			return getLanguage().getLanguage().compareTo(
					other.getLanguage().getLanguage());
		}
	}

	/**
	 * Creates and returns a new Localization that isn't connected to a Value.
	 * 
	 * @param start
	 *            Can be null.
	 */
	public static Localization create(Locale loc, String value, Date start) {
		Transaction tx = Model.db.beginTx();

		Node n = null;
		try {
			n = Model.db.createNode();
			n.setProperty(PROP_LOCALE, loc.toString());
			n.setProperty(PROP_VALUE, value);
			if (start != null) {
				n.setProperty(PROP_START, start.getTime());
			}

			tx.success();
		} catch (RuntimeException e) {
			tx.failure();
			throw e;
		} finally {
			tx.finish();
		}

		return new Localization(n);
	}

}
